/*
   Copyright (c) [2023] [魔凤啸天]
   [MFUI] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details.  
*/
#include "layout.hpp"
namespace MFUI{
	Layout::Layout(SDL_Color background,std::initializer_list<Node*>& children):
	CacheNode(children),background(background){}
	Layout::~Layout(){}
	bool Layout::confirmdraw(){return redraw|notified;}
	void Layout::setbackground(SDL_Color color){
		if(*(Uint32*)&background!=*(Uint32*)&color){
			background=color;
			redraw=true;
			notifyparent();
		}
	}
	void Layout::removechild(Window* w,size_t index){
		Node::removechild(w,index);
		redraw=true;
		notifyparent();
	}
	void Layout::removechildren(Window* w,size_t start,size_t end){
		if(start!=end){
			Node::removechildren(w,start,end);
			redraw=true;
			notifyparent();
		}
	}
	void Layout::popchildren(Window* w,size_t n){
		if(n){
			Node::popchildren(w,n);
			redraw=true;
			notifyparent();
		}
	}
	void Layout::addchild(Window* w,Node* n){
		Node::addchild(w,n);
		redraw=true;
		notifyparent();
	}
	void Layout::addchildren(Window* w,std::initializer_list<Node*> l){
		Node::addchildren(w,l);
		redraw=true;
		notifyparent();
	}
	void Layout::insertchild(Window* w,Node* n,size_t index){
		Node::insertchild(w,n,index);
		redraw=true;
		notifyparent();
	}
	void Layout::insertchildren(Window* w,std::initializer_list<Node*> l,size_t index){
		Node::insertchildren(w,l,index);
		redraw=true;
		notifyparent();
	}
	void Layout::swapchild(size_t a,size_t b){
		if(a!=b){
			auto na=children[a],nb=children[b];
			children[b]=na,children[a]=nb;
			std::swap((SDL_FRect&)na->getrect(),(SDL_FRect&)nb->getrect());
			na->forceredraw(),nb->forceredraw();
			notified=true;
			notifyparent();
		}
	}

	BoxLayout::~BoxLayout(){}
	BoxLayout::BoxLayout(SDL_Color background,float tmargin,float bmargin,
	float lmargin,float rmargin,float sep,std::initializer_list<Node*>& children):
	Layout(background,children),tmargin(tmargin),bmargin(bmargin),
	lmargin(lmargin),rmargin(rmargin),sep(sep){}
	void BoxLayout::setmargin(float t,float b,float l,float r){
		tmargin=t,bmargin=b,lmargin=l,rmargin=r;
		redraw=true;
		notifyparent();
	}
	void BoxLayout::setseparate(float sep){
		this->sep=sep;
		redraw=true;
		notifyparent();
	}
	
	VBoxLayout::VBoxLayout(SDL_Color background,float tmargin,float bmargin,
	float lmargin,float rmargin,float sep,std::initializer_list<Node*> children):
	BoxLayout(background,tmargin,bmargin,lmargin,rmargin,sep,children){}
	void VBoxLayout::draw(Renderer* r,bool updatecache){
		if(redraw|updatecache){
			CacheNode::_draw(r,updatecache);
			redraw=false;
			notified=false;
			auto b=&rect;
			auto back=background;
			r->setdrawcolor(back);
			r->fillrectF(b);
			auto bw=b->w,bh=b->h;
			auto lmargin=this->lmargin*bw;
			auto tmargin=this->tmargin*bh;
			SDL_FRect _={b->x+lmargin,b->y+tmargin,
			bw-rmargin*bw-lmargin,bh-bmargin*bh-tmargin};
			auto size=children.size();
			auto sep=this->sep*bh;
			if(size)_.h=(_.h-sep*(size-1))/size;
			for(auto v:children){
				(SDL_FRect&)v->getrect()=_;
				v->forceredraw();
				v->draw(r,true);
				_.y+=_.h+sep;
			}
			makecircle(r,rect);
			return;
		}
		notified=false;
		for(auto v:children){
			if(v->confirmdraw()){
				v->draw(r,updatecache);
			}
		}
		makecircle(r,rect);
	}
	HBoxLayout::HBoxLayout(SDL_Color background,float tmargin,float bmargin,
	float lmargin,float rmargin,float sep,std::initializer_list<Node*> children):
	BoxLayout(background,tmargin,bmargin,lmargin,rmargin,sep,children){}
	void HBoxLayout::draw(Renderer* r,bool updatecache){
		if(redraw|updatecache){
			CacheNode::_draw(r,updatecache);
			redraw=false;
			notified=false;
			auto b=&rect;
			auto back=background;
			r->setdrawcolor(back);
			r->fillrectF(b);
			auto bw=b->w,bh=b->h;
			auto lmargin=this->lmargin*bw;
			auto tmargin=this->tmargin*bh;
			SDL_FRect _={b->x+lmargin,b->y+tmargin,
			bw-rmargin*bw-lmargin,bh-bmargin*bh-tmargin};
			auto size=children.size();
			auto sep=this->sep*bw;
			if(size)_.w=(_.w-sep*(size-1))/size;
			for(auto v:children){
				(SDL_FRect&)v->getrect()=_;
				v->forceredraw();
				v->draw(r,true);
				_.x+=_.w+sep;
			}
			makecircle(r,rect);
			return;
		}
		notified=false;
		for(auto v:children){
			if(v->confirmdraw()){
				v->draw(r,updatecache);
			}
		}
		makecircle(r,rect);
	}
	VSepLayout::VSepLayout(SDL_Color background,float tmargin,float bmargin,
	float lmargin,float rmargin,float sep,std::initializer_list<Node*> children):
	BoxLayout(background,tmargin,bmargin,lmargin,rmargin,sep,children){}
	void VSepLayout::draw(Renderer* r,bool updatecache){
		if(redraw|updatecache){
			CacheNode::_draw(r,updatecache);
			redraw=false;
			notified=false;
			auto b=&rect;
			auto back=background;
			auto bw=b->w,bh=b->h;
			auto lmargin=this->lmargin*bw;
			auto tmargin=this->tmargin*bh;
			auto w=bw-lmargin-rmargin*bw,h=bh-tmargin-bmargin*bh;
			auto sep=this->sep*h;
			r->setdrawcolor(back);
			r->fillrectF(b);
			if(children.size()){
				auto v=children[0];
				SDL_FRect _{b->x+lmargin,b->y+tmargin,w,sep};
				(SDL_FRect&)v->getrect()=_;
				v->forceredraw();
				v->draw(r,true);
				_.y+=_.h;
				_.h=h-_.h;
				for(auto b=children.begin()+1,e=children.end();b!=e;b++){
					v=*b;
					(SDL_FRect&)v->getrect()=_;
					v->forceredraw();
					v->draw(r,true);
				}
			}
			makecircle(r,rect);
			return;
		}
		notified=false;
		if(children.size()){
			auto v=children[0];
			if(v->confirmdraw()){
				v->draw(r,updatecache);
			}
			bool confirm=false;
			for(auto b=children.begin()+1,e=children.end();b!=e;b++){
				confirm|=(*b)->confirmdraw();
			}
			if(confirm){
				for(auto b=children.begin()+1,e=children.end();b!=e;b++){
					(*b)->draw(r,updatecache);
				}
			}
		}
		makecircle(r,rect);
	}
	HSepLayout::HSepLayout(SDL_Color background,float tmargin,float bmargin,
	float lmargin,float rmargin,float sep,std::initializer_list<Node*> children):
	BoxLayout(background,tmargin,bmargin,lmargin,rmargin,sep,children){}
	void HSepLayout::draw(Renderer* r,bool updatecache){
		if(redraw|updatecache){
			CacheNode::_draw(r,updatecache);
			redraw=false;
			notified=false;
			auto b=&rect;
			auto back=background;
			auto bw=b->w,bh=b->h;
			auto lmargin=this->lmargin*bw;
			auto tmargin=this->tmargin*bh;
			auto w=bw-lmargin-rmargin*bw,h=bh-tmargin-bmargin*bh;
			auto sep=this->sep*w;
			r->setdrawcolor(back);
			r->fillrectF(b);
			if(children.size()){
				auto v=children[0];
				SDL_FRect _{b->x+lmargin,b->y+tmargin,sep,h};
				(SDL_FRect&)v->getrect()=_;
				v->forceredraw();
				v->draw(r,true);
				_.x+=_.w;
				_.w=w-_.w;
				for(auto b=children.begin()+1,e=children.end();b!=e;b++){
					v=*b;
					(SDL_FRect&)v->getrect()=_;
					v->forceredraw();
					v->draw(r,true);
				}
			}
			makecircle(r,rect);
			return;
		}
		notified=false;
		if(children.size()){
			auto v=children[0];
			if(v->confirmdraw()){
				v->draw(r,updatecache);
			}
			bool confirm=false;
			for(auto b=children.begin()+1,e=children.end();b!=e;b++){
				confirm|=(*b)->confirmdraw();
			}
			if(confirm){
				for(auto b=children.begin()+1,e=children.end();b!=e;b++){
					(*b)->draw(r,updatecache);
				}
			}
		}
		makecircle(r,rect);
	}
}